#include "visibility.h"

namespace poly
{
	Visibility::Visibility(){
		m_VisTri.center		= float3(0, 0, 0);
		m_VisTri.vertex1	= float3(0, 0, 0);
		m_VisTri.vertex2	= float3(0, 0, 0);

		m_VisProp.angle	= 0.0f;
		m_VisProp.distance	= 0.0f;
		m_VisProp.speed	= 150.0f;
		m_VisState.stateFunctionStep = VIS_GRAD;
		m_VisState.statePolygon = VIS_ON;
		m_VisProp.visionPerc = 0.0f;
		m_VisState.see		= VIS_OFF;
	}
	Visibility::Visibility(float3 center, float angle, float distance){
		m_VisTri.center			= center;
		m_VisProp.angle		= angle;
		m_VisProp.distance		= distance;
		m_VisProp.visionPerc	= 0.0f;
		m_VisProp.speed		= 100.0f;
		m_VisState.stateFunctionStep	= VIS_GRAD;
		m_VisState.statePolygon			= VIS_ON;
		m_VisState.see			= VIS_OFF;

		setPoly(center);
	}
	bool	Visibility::setState(int prop, int value){
		switch(prop)
		{
		case VIS_FUNCTION_STEP:
			m_VisState.stateFunctionStep = value;
			return true;
		default:
			return false;
		}
	}
	bool	Visibility::setState(int prop, bool value){
		switch(prop)
		{
		case VIS_POLYGON:
			m_VisState.statePolygon = value;
			return true;
		default:
			return false;
		}
	}
	bool	Visibility::setProp(int prop, float value){
		switch(prop)
		{
		case VIS_DISTANCE:
			m_VisProp.distance = value;
			return true;
		case VIS_ANGLE:
			m_VisProp.angle = value;
			return true;
		case VIS_SPEED:
			m_VisProp.speed = value;
			return true;
		default:
			return false;
		}
	}
	float3	Visibility::getVisTri(int prop){
		switch(prop)
		{
		case VIS_TRI_CENTER:
			return m_VisTri.center;
		case VIS_TRI_VERTEX1:
			return m_VisTri.vertex1;
		case VIS_TRI_VERTEX2:
			return m_VisTri.vertex2;
		default:
			return float3(0,0,0);
		}
	}

	int		Visibility::getState(int state){
		switch(state)
		{
		case VIS_FUNCTION_STEP:
			return m_VisState.stateFunctionStep;
		case VIS_POLYGON:
			return m_VisState.statePolygon;
		default:
			return 0;
		}
	}
	float	Visibility::getProp(int prop){
		switch(prop)
		{
		case VIS_DISTANCE:
			return m_VisProp.distance;
		case VIS_ANGLE:
			return m_VisProp.angle;
		case VIS_SPEED:
			return m_VisProp.speed;
		case VIS_VISPERC:
			return m_VisProp.visionPerc;
		default:
			return 0.0f;
		}
	}
	Polygon Visibility::getPoly(){
		return m_VisPoly;
	}
	void	Visibility::setPoly(float3 center){
		m_VisPoly.empty();
		//Center of the Object
		m_VisPoly.push_back(center);
		//Vertex I
		m_VisTri.vertex1 =	float3((cos(45-m_VisProp.angle/2)*cos(m_VisProp.angle/2)*m_VisProp.distance + center.x),
							(sin(45-m_VisProp.angle/2)*cos(m_VisProp.angle/2)*m_VisProp.distance + center.y),
							0);
		m_VisPoly.push_back(m_VisTri.vertex1);
		//Vertex II
		m_VisTri.vertex2 =	float3((sin(45-m_VisProp.angle/2)*cos(m_VisProp.angle/2)*m_VisProp.distance + center.x),
							(cos(45-m_VisProp.angle/2)*cos(m_VisProp.angle/2)*m_VisProp.distance + center.y),
							0);
		m_VisPoly.push_back(m_VisTri.vertex2);
	}

	bool	Visibility::verify(int prop, float value){
		switch(prop)
		{
		case VIS_DISTANCE:
			if(m_VisProp.distance == value)	{return true;}
			else {return false;}
		case VIS_ANGLE:
			if(m_VisProp.angle == value)	{return true;}
			else {return false;}
		case VIS_SPEED:
			if(m_VisProp.speed == value)	{return true;}
			else {return false;}
		default:
			return false;
		}
	}
	bool	Visibility::verify(int prop, int value){
		switch(prop)
		{
		case VIS_FUNCTION_STEP:
			if(m_VisState.stateFunctionStep == value) {return true;}
			else {return false;}
		default:
			return false;
		}
	}
	bool	Visibility::verify(int prop, bool value){
		switch(prop)
		{
		case VIS_POLYGON:
			if(m_VisState.statePolygon == value) {return true;}
			else {return false;}
		default:
			return false;
		}
	}
	void	Visibility::updateTri(float3 center, float rotationalSpeed){
		float44 rotate;
		D3DXMatrixRotationZ(&rotate, rotationalSpeed);
		m_VisPoly = m_VisPoly.transform(rotate);

		m_VisTri.vertex1 += (center - m_VisTri.center);
		m_VisTri.vertex2 += (center - m_VisTri.center);
		m_VisTri.center = center;

		m_VisTri.vertex1 = transformCoord(m_VisTri.vertex1, rotate);
		m_VisTri.vertex2 = transformCoord(m_VisTri.vertex2, rotate);
		m_VisTri.center = transformCoord(m_VisTri.center, rotate);
	}

	bool	Visibility::canSee(float radius, float3 center){
		if(m_VisState.statePolygon == VIS_ON){
			if(m_VisState.see == VIS_OFF) m_VisProp.visionPerc = 0;
			if(m_VisProp.visionPerc > 100) m_VisProp.visionPerc = 100;
			else if((m_VisState.see == VIS_ON) && (m_VisState.stateFunctionStep == VIS_GRAD))
				m_VisProp.visionPerc += pow(1/length(center-m_VisTri.center),2)*m_VisProp.speed;
			else if((m_VisState.see == VIS_ON) && (m_VisState.stateFunctionStep == VIS_BOOL))
				m_VisProp.visionPerc = 100.0f;

			//Left Edge Test
			float3 left_edge = m_VisTri.center - m_VisTri.vertex2;
			float3 normal = float3(-1*left_edge.y, left_edge.x, 0.0f);
			float distanceFromOrigin = dot(normal, m_VisTri.center);
			float check_left = dot(normal,center)-distanceFromOrigin;

			//Right Edge Test
			float3 right_edge = m_VisTri.vertex1 - m_VisTri.center;
			normal = float3(-1*right_edge.y, right_edge.x, 0.0f);
			distanceFromOrigin = dot(normal, m_VisTri.center);
			float check_right = dot(normal,center)-distanceFromOrigin;

			//Far Edge Test
			float3 far_edge = m_VisTri.vertex2 - m_VisTri.vertex1;
			normal = float3(-1*far_edge.y, far_edge.x, 0.0f);
			distanceFromOrigin = dot(normal, m_VisTri.vertex1);
			float check_far = dot(normal,center)-distanceFromOrigin;
			
			if((check_left+radius > 0)&&(check_right+radius > 0)&&(check_far+radius > 0)){m_VisState.see = VIS_ON;}
			else	m_VisState.see = VIS_OFF;

			if(m_VisProp.visionPerc >= 100 && m_VisState.see == VIS_ON)	return true;
			else	return false;
		}
		return false;
	}

	void	Visibility::reset(float3 center, float angle, float distance){
		m_VisTri.center			= center;
		m_VisProp.angle			= angle;
		m_VisProp.distance		= distance;
		m_VisProp.visionPerc	= 0.0f;
		m_VisProp.speed			= 100.0f;
		m_VisState.stateFunctionStep	= VIS_GRAD;
		m_VisState.statePolygon			= VIS_ON;
		m_VisState.see					= VIS_OFF;

		setPoly(center);
	}
}
